using System;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Xml;
using Deepcode.Flux.Core.Collections;
using Deepcode.Flux.Core.Services.Errors;
using Deepcode.Flux.Core.Services.FileSystem;
using Deepcode.Flux.Core.Services.Configuration;
using Deepcode.Flux.Core.UI.Interfaces;
using System.Collections.Specialized;
using Deepcode.Flux.Core.Systems.Addins;
using Deepcode.Flux.Core.Systems.Security;
using Deepcode.Flux.Core.Services.Installation;
using Deepcode.Flux.Core.Data;

public partial class Setup_Process_Default : Deepcode.Flux.Core.UI.NonCachePage
{
	#region Page_Load
	protected void Page_Load(object sender, EventArgs e)
	{
		// Begin the installation
		ProcessInstallSession();
	}
	#endregion
	#region ProcessInstallSession()
	/// <summary>
	/// ProcessInstallSession will load the manifest specified by the URL parameter ifile
	/// and will interrogate the database for the application version that is presently installed
	/// it will then examine what commands should be executed for the currently installed version
	/// to update it to the next version in the chain (as specified in the manifest).
	/// </summary>
	protected void ProcessInstallSession()
	{
		SqlConnection c = null;
		SqlTransaction t = null;

		try
		{
			// Read the manifest
			panels.BeginItem("Reading manifest");
			Manifest m = new Manifest();
			m.LoadCommandset( Server.MapPath(Request["ifile"]) );
			panels.EndItem(Deepcode.Flux.Core.UI.Controls.Special.UpdatePanels.States.OK);
			
			// Connect to the database and begin a transaction
			c = new SqlConnection( FluxConfig.MainDSN );
			c.Open();
			t = c.BeginTransaction();

			// Process the commandset read for the current version
			foreach (XmlNode n in m.CommandsetNodes)
				ExecuteCommand( m, n, c, t );

			// Commit the transaction and close the connection
			t.Commit();
			c.Close();

			// Finished
			if( Request["finish"] != null ) panels.FinishedUrl = Request["finish"];
			else panels.FinishedUrl = "~/admin";
			panels.Success();
		}
		catch( Exception e )
		{
			// Swap panels into an error state
			panels.Error( e );
			
			// Rollback the transaction
			try
			{
				if (t != null)
				{
					panels.BeginItem("Rolling back transaction");
					t.Rollback();
					panels.EndItem(Deepcode.Flux.Core.UI.Controls.Special.UpdatePanels.States.OK);
				}
			} 
			catch 
			{
				panels.EndItem(Deepcode.Flux.Core.UI.Controls.Special.UpdatePanels.States.FAIL);
			}

			// Close the database
			try
			{
				if (t != null)
				{
					panels.BeginItem("Closing db connection");
					c.Close();
					panels.EndItem(Deepcode.Flux.Core.UI.Controls.Special.UpdatePanels.States.OK);
				}
			}
			catch
			{
				panels.EndItem(Deepcode.Flux.Core.UI.Controls.Special.UpdatePanels.States.FAIL);
			}

			// Failed, but cleanly
			panels.BeginEndItem("Installation failed - transaction rolled back", Deepcode.Flux.Core.UI.Controls.Special.UpdatePanels.States.OK);
		}
	}
	#endregion
	#region Command processor
	/// <summary>
	/// ExecuteCommand determines what action to take based upon the xml tag for the command
	/// </summary>
	/// <param name="m"></param>
	/// <param name="cmd"></param>
	/// <param name="c"></param>
	/// <param name="t"></param>
	protected void ExecuteCommand(Manifest m, XmlNode cmd, SqlConnection c, SqlTransaction t)
	{
		if( cmd.Name == "Log" )
			panels.BeginEndItem( cmd.InnerText, Deepcode.Flux.Core.UI.Controls.Special.UpdatePanels.States.NOSTATE );

		if( cmd.Name == "ErrorLog" )
			panels.WriteNotice( cmd.InnerText );

		if (cmd.Name == "SQLBatch")
			ProcessSQLBatch( cmd.InnerText, c, t );

		if( cmd.Name == "SQLDirectory")
			ProcessSQLDirectory( cmd.InnerText, c, t );

		if (cmd.Name == "SetVersion")
		{
			KnownAddins addins = new KnownAddins(c, t);
			KnownAddin ka = addins.GetByGuid(m.ApplicationGuid);
			if (ka == null)
			{
				ka = new KnownAddin();
				ka.AddinName = m.ApplicationName;
				ka.GUID = m.ApplicationGuid;
			}
			ka.VersionString = cmd.InnerText;
			addins.Save(ka);
		}
	}
	#endregion
	#region Command handlers
	/// <summary>
	/// Process a single SQL batch file
	/// </summary>
	/// <param name="SQLFile"></param>
	/// <param name="c"></param>
	/// <param name="t"></param>
	private void ProcessSQLBatch(string SQLFile, SqlConnection c, SqlTransaction t)
	{
		try
		{
			Deepcode.Flux.Core.Data.SQLBatchProcessor sb = new SQLBatchProcessor();
			sb.ExecuteQueryScriptSQLFile(Server.MapPath(SQLFile), c, t);
		}
		catch (Exception e)
		{
			string msg = String.Format("Error occurred processing file: {0}", SQLFile);
			throw new Exception(msg, e);
		}
	}
	/// <summary>
	/// Scans an entire directory for sql files and executes them all
	/// </summary>
	/// <param name="path"></param>
	/// <param name="c"></param>
	/// <param name="t"></param>
	private void ProcessSQLDirectory(string path, SqlConnection c, SqlTransaction t)
	{
		Deepcode.Flux.Core.Services.FileSystem.FileScanService fs = new FileScanService();
		StringCollection files = fs.SearchFilesInWebPath( path, "*.sql", true );
		foreach (string file in files)
		{
			try
			{
				Deepcode.Flux.Core.Data.SQLBatchProcessor sb = new SQLBatchProcessor();
				sb.ExecuteQueryScriptSQLFile(file, c, t);
			}
			catch (Exception e)
			{
				string msg = String.Format("Error occurred processing file: {0}", file);
				throw new Exception(msg, e);
			}
		}
	}
	#endregion
}
